package vcsn.utils;

import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
 



import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import vcsn.Config;
import vcsn.RelationMapExportConfig;
import vcsn.entities.*;
import vcsn.entities.Class;
import vcsn.entities.Relation.Type;
import vcsn.entities.RelationMapDiff.Status;
import vcsn.entities.Variable.Multiplexity;

public class ExportImportHandler {
	public static File exportRelationMapToXML(List<Class> relationMap, String projetctName){
		if(relationMap == null){
			return null;
		}
		try {
			HashMap<String, List<Class>> mapList = ExportImportHandler.importAllRelationMapFromXML(projetctName);
			mapList.put(projetctName, relationMap);
						
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
	 
			// root elements
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement(RelationMapExportConfig.relationMapNode);
			rootElement.setAttribute(RelationMapExportConfig.buildDateAttribute, new SimpleDateFormat(Config.FormattedDateTimeString).format(new Date()));
			doc.appendChild(rootElement);
			for(String project : mapList.keySet()){
				List<Class> relationMapValue = mapList.get(project);
				Element projectElement = doc.createElement(RelationMapExportConfig.projectNode);
				rootElement.appendChild(projectElement);
				
				projectElement.setAttribute(RelationMapExportConfig.projectNameAttribute, project);

				// class elements
				for(Class classEntity : relationMapValue){
					Element entityElement = doc.createElement(RelationMapExportConfig.classNode);
					projectElement.appendChild(entityElement);

					// set attributes to class element
					entityElement.setAttribute(RelationMapExportConfig.idAttribute, classEntity.id);
					entityElement.setAttribute(RelationMapExportConfig.modifiersAttribute, Integer.toString(classEntity.modifier));
					entityElement.setAttribute(RelationMapExportConfig.fileNameAttribute, classEntity.filename);
					entityElement.setAttribute(RelationMapExportConfig.declarationLineNumberAttribute, Integer.toString(classEntity.declarationLineNumber));
					
					// Superclass and Interfaces Elements
					if(classEntity.generalizationAndRealization.length > 0){
						for(Relation generalizationAndRealization : classEntity.generalizationAndRealization){
							Element generalizationAndRealizationElement = doc.createElement(RelationMapExportConfig.generalizationAndRealizationNode);
							entityElement.appendChild(generalizationAndRealizationElement);

							generalizationAndRealizationElement.setAttribute(RelationMapExportConfig.idAttribute, generalizationAndRealization.targetId);
							generalizationAndRealizationElement.setAttribute(RelationMapExportConfig.relationTypeAttribute, generalizationAndRealization.type.toString());
							generalizationAndRealizationElement.setAttribute(RelationMapExportConfig.declarationLineNumberAttribute, Integer.toString(generalizationAndRealization.declarationLineNumber));
						}
					}

					// Variables Elements
					for(Variable variable : classEntity.variables){
						Element variableElement = doc.createElement(RelationMapExportConfig.variableNode);
						entityElement.appendChild(variableElement);

						variableElement.setAttribute(RelationMapExportConfig.idAttribute, variable.id);
						variableElement.setAttribute(RelationMapExportConfig.modifiersAttribute, Integer.toString(variable.modifier));
						variableElement.setAttribute(RelationMapExportConfig.vriableTypeAttribute, variable.association.targetId);
						variableElement.setAttribute(RelationMapExportConfig.relationTypeAttribute, variable.association.type.toString());
						variableElement.setAttribute(RelationMapExportConfig.multiplexityAttribute, variable.multiplexity.toString());
						variableElement.setAttribute(RelationMapExportConfig.declarationLineNumberAttribute, Integer.toString(variable.declarationLineNumber));
					}

					// Method Elements
					for(Method method : classEntity.methods){
						Element methodElement = doc.createElement(RelationMapExportConfig.methodNode);
						entityElement.appendChild(methodElement);

						methodElement.setAttribute(RelationMapExportConfig.idAttribute, method.id);
						methodElement.setAttribute(RelationMapExportConfig.modifiersAttribute, Integer.toString(method.modifier));
						methodElement.setAttribute(RelationMapExportConfig.declarationLineNumberAttribute, Integer.toString(method.declarationLineNumber));
						
						for(Relation parameter : method.parameterDependency){
							Element methodParameterElement = doc.createElement(RelationMapExportConfig.parameterNode);
							methodElement.appendChild(methodParameterElement);
							methodParameterElement.setAttribute(RelationMapExportConfig.parameterTypeAttribute, parameter.targetId);
							methodParameterElement.setAttribute(RelationMapExportConfig.parameterTypeRelationTypeAttribute, parameter.type.toString());
							methodParameterElement.setAttribute(RelationMapExportConfig.declarationLineNumberAttribute, Integer.toString(parameter.declarationLineNumber));
						}
						
						if(method.returnValueDependency != null){
							Element methodReturnTypeElement = doc.createElement(RelationMapExportConfig.returnTypeNode);
							methodElement.appendChild(methodReturnTypeElement);
							methodReturnTypeElement.setAttribute(RelationMapExportConfig.returnTypeAttribute, method.returnValueDependency.targetId);
							methodReturnTypeElement.setAttribute(RelationMapExportConfig.returnTypeRelationTypeAttribute, method.returnValueDependency.type.toString());
							methodReturnTypeElement.setAttribute(RelationMapExportConfig.declarationLineNumberAttribute, Integer.toString(method.returnValueDependency.declarationLineNumber));
						}
					}
				}
			}
			//create destination path
			File relationMapFile = new File(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.relaitonMapFile);
			
			if(relationMapFile.exists()){
				relationMapFile.delete();
			}
			
			// write the content into XML file
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(relationMapFile);
			transformer.transform(source, result);
			return relationMapFile;
	 
		  } catch (ParserConfigurationException pce) {
			pce.printStackTrace();
			return null;
		  } catch (TransformerException tfe) {
			tfe.printStackTrace();
			return null;
		  }
	}
	
	public static List<Class> importRelationMapFromXML(String relationMapFileAbsolutePath, String projectName){
		HashMap<String, List<Class>> mapWithAllProjects = ExportImportHandler.importAllRelationMapFromXML(relationMapFileAbsolutePath);
		if(mapWithAllProjects.size() >= 1){
			List<Class> returnMap = new ArrayList<Class>();
			returnMap = mapWithAllProjects.get(projectName);
			if(returnMap == null){
				return new ArrayList<Class>();
			}
			return returnMap;
		}else{
			return new ArrayList<Class>();
		}
	}
	
	public static HashMap<String, List<Class>> importAllRelationMapFromXML(String relationMapFileAbsolutePath){
		File sourceFile = new File(relationMapFileAbsolutePath);
		if(!sourceFile.exists()){
			return new HashMap<String, List<Class>>();
		}
		try {
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse (sourceFile);
            Class[] relationMap = null;
            HashMap<String, List<Class>> mapWithAllProjects = new HashMap<String, List<Class>>();
            
            // Normalize text representation
            doc.getDocumentElement ().normalize ();

            // Build relation map
            
            // Get relation map nodes
            NodeList mapList = doc.getElementsByTagName(RelationMapExportConfig.relationMapNode);
            for(int i = 0; i < mapList.getLength(); i++){
            	
            	// Append map attributes
            	Node nodeItem = mapList.item(i);
            	if(nodeItem.getNodeType() == Node.ELEMENT_NODE){
            		Element  mapElement = (Element)nodeItem;
            		
            		NodeList projectNodeList = mapElement.getElementsByTagName(RelationMapExportConfig.projectNode);
            		
            		for(int j = 0; j < projectNodeList.getLength(); j++){
            			Node projectNodeItem = projectNodeList.item(j);
            			if(projectNodeItem.getNodeType() == Node.ELEMENT_NODE){
            				Element  projectElement = (Element)projectNodeItem;
            				
            				String projectName = projectElement.getAttribute(RelationMapExportConfig.projectNameAttribute);

            				// Get class nodes
            				NodeList classNodeList 	= projectElement.getElementsByTagName(RelationMapExportConfig.classNode);
            				relationMap 			= new Class[classNodeList.getLength()];

            				// Apply Class Attributes
            				for(int k = 0; k < classNodeList.getLength(); k++){
            					Node classNodeItem = classNodeList.item(k);
            					if(classNodeItem.getNodeType() == Node.ELEMENT_NODE){
            						Element  classElement = (Element)classNodeItem;

            						relationMap[k]							= new Class();
            						relationMap[k].id 						= classElement.getAttribute(RelationMapExportConfig.idAttribute);
            						relationMap[k].filename 				= classElement.getAttribute(RelationMapExportConfig.fileNameAttribute);
            						relationMap[k].declarationLineNumber 	= Integer.parseInt(classElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));
            						relationMap[k].modifier 				= Integer.parseInt(classElement.getAttribute(RelationMapExportConfig.modifiersAttribute));

            						//    	            		System.out.println("Class ID: " 		+ relationMap[j].id);
            						//    	            		System.out.println("Class Location: " 	+ relationMap[j].filename);

            						// Get Generalization And Realization Elements
            						NodeList generalizationAndRealizationNodeList 	= classElement.getElementsByTagName(RelationMapExportConfig.generalizationAndRealizationNode);
            						relationMap[k].generalizationAndRealization 	= new Relation[generalizationAndRealizationNodeList.getLength()];

            						// Apply Generalization And Realization attributes
            						for(int l = 0; l < generalizationAndRealizationNodeList.getLength(); l++){
            							Node  generalizationAndRealizationNodeItem = generalizationAndRealizationNodeList.item(l);
            							if(generalizationAndRealizationNodeItem.getNodeType() == Node.ELEMENT_NODE){
            								Element  generalizationAndRealizationElement = (Element)generalizationAndRealizationNodeItem;

            								relationMap[k].generalizationAndRealization[l] 							= new Relation();
            								relationMap[k].generalizationAndRealization[l].type 					= Type.valueOf(generalizationAndRealizationElement.getAttribute(RelationMapExportConfig.relationTypeAttribute));
            								relationMap[k].generalizationAndRealization[l].targetId 				= generalizationAndRealizationElement.getAttribute(RelationMapExportConfig.idAttribute);
            								relationMap[k].generalizationAndRealization[l].declarationLineNumber 	= Integer.parseInt(generalizationAndRealizationElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));

            								//    	            				System.out.println("Relation Type: " 	+ relationMap[j].generalizationAndRealization[k].type);
            								//    	    	            		System.out.println("Relation ID: " 		+ relationMap[j].generalizationAndRealization[k].targetId);
            							}
            						}

            						// Get Variable Elements
            						NodeList variableNodeList 	= classElement.getElementsByTagName(RelationMapExportConfig.variableNode);
            						relationMap[k].variables 	= new Variable[variableNodeList.getLength()];

            						// Apply Variable Attributes
            						for(int l = 0; l < variableNodeList.getLength(); l++){
            							Node  variableNodeItem = variableNodeList.item(l);
            							if(variableNodeItem.getNodeType() == Node.ELEMENT_NODE){
            								Element  variablenElement = (Element)variableNodeItem;

            								relationMap[k].variables[l] 						= new Variable();
            								relationMap[k].variables[l].association 			= new Relation();
            								relationMap[k].variables[l].association.type 		= Type.valueOf(variablenElement.getAttribute(RelationMapExportConfig.relationTypeAttribute));
            								relationMap[k].variables[l].association.targetId 	= variablenElement.getAttribute(RelationMapExportConfig.vriableTypeAttribute);
            								relationMap[k].variables[l].id 						= variablenElement.getAttribute(RelationMapExportConfig.idAttribute);
            								relationMap[k].variables[l].multiplexity			= Multiplexity.valueOf(variablenElement.getAttribute(RelationMapExportConfig.multiplexityAttribute));
            								relationMap[k].variables[l].declarationLineNumber 	= Integer.parseInt(variablenElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));
            								relationMap[k].variables[l].modifier 				= Integer.parseInt(variablenElement.getAttribute(RelationMapExportConfig.modifiersAttribute));

            								//    	            				System.out.println("Variable ID: " 				+ relationMap[j].variables[k].id);
            								//    	    	            		System.out.println("Variable Relation: " 		+ relationMap[j].variables[k].association.targetId);
            								//    	    	            		System.out.println("Variable Relation Type: " 	+ relationMap[j].variables[k].association.type);
            								//    	    	            		System.out.println("Variable Multiplexity: " 	+ relationMap[j].variables[k].multiplexity);
            							}
            						}

            						// Get Method Elements
            						NodeList methodNodeList 	= classElement.getElementsByTagName(RelationMapExportConfig.methodNode);
            						relationMap[k].methods 		= new Method[methodNodeList.getLength()];

            						// Apply Method Attributes
            						for(int l = 0; l < methodNodeList.getLength(); l++){
            							Node  methodNodeItem = methodNodeList.item(l);
            							if(methodNodeItem.getNodeType() == Node.ELEMENT_NODE){
            								Element  methodElement = (Element)methodNodeItem;

            								relationMap[k].methods[l] 									= new Method();
            								relationMap[k].methods[l].id 								= methodElement.getAttribute(RelationMapExportConfig.idAttribute);
            								relationMap[k].methods[l].declarationLineNumber 			= Integer.parseInt(methodElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));
            								
//            								relationMap[k].methods[l].returnValueDependency.type 		= Type.valueOf(methodElement.getAttribute(RelationMapExportConfig.returnTypeRelationTypeAttribute));
//            								relationMap[k].methods[l].returnValueDependency.targetId 	= methodElement.getAttribute(RelationMapExportConfig.returnTypeAttribute);
//            								relationMap[k].methods[l].declarationLineNumber 			= Integer.parseInt(methodElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));
            								relationMap[k].methods[l].modifier 							= Integer.parseInt(methodElement.getAttribute(RelationMapExportConfig.modifiersAttribute));

            								//    	            				System.out.println("Method ID: " 						+ relationMap[j].methods[k].id);
            								//    	    	            		System.out.println("Method Return Type Relation: " 		+ relationMap[j].methods[k].returnValueDependency.targetId);
            								//    	    	            		System.out.println("Method Return Type Relation Type: " + relationMap[j].methods[k].returnValueDependency.type);
            								
            								// Get Return Type Elements
            								NodeList returnTypeNodeList 						= methodElement.getElementsByTagName(RelationMapExportConfig.returnTypeAttribute);
            								// Apply Return Type Attributes
            								for(int m = 0; m < returnTypeNodeList.getLength(); m++){
            									if(returnTypeNodeList.getLength() == 0){
            										relationMap[k].methods[l].returnValueDependency = null;
            									}else{
            										relationMap[k].methods[l].returnValueDependency	= new Relation();
            									}
            									Node  returnTypeNodeItem = returnTypeNodeList.item(m);
            									if(methodNodeItem.getNodeType() == Node.ELEMENT_NODE){
            										Element  returnTypeElement = (Element)returnTypeNodeItem;
            										
            										relationMap[k].methods[l].returnValueDependency.type 					= Type.valueOf(returnTypeElement.getAttribute(RelationMapExportConfig.returnTypeRelationTypeAttribute));
                    								relationMap[k].methods[l].returnValueDependency.targetId 				= returnTypeElement.getAttribute(RelationMapExportConfig.returnTypeAttribute);
                    								relationMap[k].methods[l].returnValueDependency.declarationLineNumber 	= Integer.parseInt(returnTypeElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));
            									}
            								}

            								// Get Parameter Elements
            								NodeList parameterNodeList 						= methodElement.getElementsByTagName(RelationMapExportConfig.parameterNode);
            								relationMap[k].methods[l].parameterDependency 	= new Relation[parameterNodeList.getLength()];

            								// Apply Parameter Attributes
            								for(int m = 0; m < parameterNodeList.getLength(); m++){
            									Node  parameterNodeItem = parameterNodeList.item(m);
            									if(methodNodeItem.getNodeType() == Node.ELEMENT_NODE){
            										Element  parameterElement = (Element)parameterNodeItem;

            										relationMap[k].methods[l].parameterDependency[m] 						= new Relation();
            										relationMap[k].methods[l].parameterDependency[m].targetId 				= parameterElement.getAttribute(RelationMapExportConfig.parameterTypeAttribute);
            										relationMap[k].methods[l].parameterDependency[m].type 					= Type.valueOf(parameterElement.getAttribute(RelationMapExportConfig.parameterTypeRelationTypeAttribute));
            										relationMap[k].methods[l].parameterDependency[m].declarationLineNumber 	= Integer.parseInt(parameterElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));

            										//    	    	    	            		System.out.println("Method Parameter Type Relation: " 		+ relationMap[j].methods[k].parameterDependency[l].targetId);
            										//    	    	    	            		System.out.println("Method Parameter Type Relation Type: " 	+ relationMap[j].methods[k].parameterDependency[l].type);
            									}
            								}
            							}
            						}
    							// end of class node}
            					}
        					}
            			// end of project node
            				List<Class> reationMap = new ArrayList<Class>();
            	            for(Class c : relationMap){
            	            	reationMap.add(c);
            	            }
            	            relationMap = null;
            	            mapWithAllProjects.put(projectName, reationMap);
        				}
            		}
            	}
            }
//            List<Class> returnMap = new ArrayList<Class>();
//            for(Class c : relationMap){
//            	returnMap.add(c);
//            }
            return mapWithAllProjects;
	    }catch (SAXParseException err) {
		    System.out.println ("** Parsing error" + ", line " + err.getLineNumber () + ", uri " + err.getSystemId () + "**");
		    System.out.println(" " + err.getMessage ());
		    return null;
	    }catch (SAXException e) {
	        Exception x = e.getException ();
	        ((x == null) ? e : x).printStackTrace ();
	        return null;
	    }catch (Throwable t) {
	        t.printStackTrace ();
	        return null;
	    }
	}
	
	public static File exportRelationMapDiffToXML(List<RelationMapDiff> relationMapDiffList, String projetctAbsolutePath){
		if(relationMapDiffList == null){
			System.out.println("relationMap is null.");
			return null;
		}
		try {
			
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
	 
			// root elements
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement(RelationMapExportConfig.relationMapDiffListNode);
			rootElement.setAttribute(RelationMapExportConfig.buildDateAttribute, new SimpleDateFormat("yyyy/MM/dd HH:mm").format(new Date()));
			doc.appendChild(rootElement);
	 
			// diffEntry elements
			for(RelationMapDiff diffEntry : relationMapDiffList){
				Element entityElement = doc.createElement(RelationMapExportConfig.relationMapDiffEntryNode);
				rootElement.appendChild(entityElement);
		 
				// set attributes to class element
				entityElement.setAttribute(RelationMapExportConfig.diffEntityTypeAttribute, diffEntry.entityType.toString());
				entityElement.setAttribute(RelationMapExportConfig.diffEntityIdentityAttribute, diffEntry.entityIdentity);				
				entityElement.setAttribute(RelationMapExportConfig.diffEntityStatusAttribute, diffEntry.entityStatus.toString());
				entityElement.setAttribute(RelationMapExportConfig.modifiersAttribute, Integer.toString(diffEntry.modifier));
				entityElement.setAttribute(RelationMapExportConfig.declarationLineNumberAttribute, Integer.toString(diffEntry.declarationLineNumber));
				entityElement.setAttribute(RelationMapExportConfig.diffEntityDefinedTypeAttribute, diffEntry.type);
				
			}
			//create destination path
			File relationMapDiffFile = Util.createTempRelationMapDiffPatchFile();
			
			if(relationMapDiffFile.exists()){
				relationMapDiffFile.delete();
			}
			
			// write the content into XML file
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(relationMapDiffFile);
	 	 
			transformer.transform(source, result);
	 
			return relationMapDiffFile;
	 
		  } catch (ParserConfigurationException pce) {
			pce.printStackTrace();
			return null;
		  } catch (TransformerException tfe) {
			tfe.printStackTrace();
			return null;
		  }
	}
	
	public static List<RelationMapDiff> importRelationMapDiffFromXML(String relationMapDiffFileAbsolutePath){
//		System.out.println("Source file: " + xmlFileAbsolutePath);
		File sourceFile = new File(relationMapDiffFileAbsolutePath);
		if(!sourceFile.exists()){
			return null;
		}
		try {
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse (sourceFile);
            List<RelationMapDiff> relationMapDiffList = new ArrayList<RelationMapDiff>();;
            
            // Normalize text representation
            doc.getDocumentElement ().normalize ();

            // Build relation map
            
            // Get relation map nodes
            NodeList mapDiffList = doc.getElementsByTagName(RelationMapExportConfig.relationMapDiffListNode);
            for(int i = 0; i < mapDiffList.getLength(); i++){
            	
            	// Append map attributes
            	Node nodeItem = mapDiffList.item(i);
            	if(nodeItem.getNodeType() == Node.ELEMENT_NODE){
            		Element  mapElement = (Element)nodeItem;
            		
            		// Get class nodes
            		NodeList diffEntryNodeList 	= mapElement.getElementsByTagName(RelationMapExportConfig.relationMapDiffEntryNode);

            		// Apply Class Attributes
            		for(int j = 0; j < diffEntryNodeList.getLength(); j++){
            			Node diffEntryNodeItem = diffEntryNodeList.item(j);
            			if(diffEntryNodeItem.getNodeType() == Node.ELEMENT_NODE){
            				Element  diffEntryElement = (Element)diffEntryNodeItem;
            				
            				RelationMapDiff diffEntry		= new RelationMapDiff();
            				diffEntry.entityIdentity 		= diffEntryElement.getAttribute(RelationMapExportConfig.diffEntityIdentityAttribute);
            				diffEntry.entityType 			= RelationMapDiff.EntityType.valueOf(diffEntryElement.getAttribute(RelationMapExportConfig.diffEntityTypeAttribute));
            				diffEntry.entityStatus 			= Status.valueOf(diffEntryElement.getAttribute(RelationMapExportConfig.diffEntityStatusAttribute));
            				diffEntry.modifier				= Integer.parseInt(diffEntryElement.getAttribute(RelationMapExportConfig.modifiersAttribute));
            				diffEntry.declarationLineNumber	= Integer.parseInt(diffEntryElement.getAttribute(RelationMapExportConfig.declarationLineNumberAttribute));
            				diffEntry.type					= diffEntryElement.getAttribute(RelationMapExportConfig.diffEntityDefinedTypeAttribute);
            				relationMapDiffList.add(diffEntry);
            			}
            		}
            		// System.out.println("end Class");
            	}
            }
            return relationMapDiffList;
	    }catch (SAXParseException err) {
		    System.out.println ("** Parsing error" + ", line " + err.getLineNumber () + ", uri " + err.getSystemId () + "**");
		    System.out.println(" " + err.getMessage ());
		    return null;
	    }catch (SAXException e) {
	        Exception x = e.getException ();
	        ((x == null) ? e : x).printStackTrace ();
	        return null;
	    }catch (Throwable t) {
	        t.printStackTrace ();
	        return null;
	    }
	}
	
	public static VectorClock importVectorClock(String clockFileAbsolutePath, String projectName){
		VectorClock clock = new VectorClock();
		
		File clockFile = new File(clockFileAbsolutePath);
		if(!clockFile.exists()){
			return clock;
		}
		HashMap<String, VectorClock> clockFromAllProject = ExportImportHandler.importVectorClockFromAllProject(clockFileAbsolutePath);
		if(clockFromAllProject.size() >= 1){
			clock = clockFromAllProject.get(projectName);
			if(clock == null){
				return new VectorClock();
			}
		}
		return clock;
	}
	
	public static String exportVectorClock(VectorClock exportedClock, String projectName){
		HashMap<String, VectorClock> importVectorClockFromAllProject = ExportImportHandler.importVectorClockFromAllProject(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.localClockFile);
		importVectorClockFromAllProject.put(projectName, exportedClock);
		try {
			File clockFile = new File(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.localClockFile);
			if(!clockFile.exists()){
				clockFile.createNewFile();
			}
		
			FileWriter fWriter = new FileWriter(clockFile, false);
			int cnt = 0;
			for(String key : importVectorClockFromAllProject.keySet()){
				String outString = "";
				outString += importVectorClockFromAllProject.get(key).toString();
				if(cnt + 1 >= importVectorClockFromAllProject.size()){
					outString = Config.propertyProjectIdentity + Config.equal + key + Config.separator + Config.propertyClockPrefix + outString;
				}else{
					outString = Config.propertyProjectIdentity + Config.equal + key + Config.separator + Config.propertyClockPrefix +  outString + "\n";
				}
				fWriter.write(outString);
				cnt++;
			}
			fWriter.flush();
			fWriter.close();
			return clockFile.getAbsolutePath();
		} catch (Exception ex){
			ex.printStackTrace();
			return null;
		}
	}
	
	public static HashMap<String, VectorClock> importVectorClockFromAllProject(String clockFileAbsolutePath){
		HashMap<String, VectorClock> importVectorClockFromAllProject = new HashMap<String, VectorClock>();
		File clockFile = new File(clockFileAbsolutePath);
		if(!clockFile.exists()){
			return importVectorClockFromAllProject;
		}
		try {
            Scanner scn = new Scanner(clockFile);
			String commitPatchListString = null;
			while(scn.hasNextLine()){
				commitPatchListString = scn.nextLine();
				if(commitPatchListString != null && !commitPatchListString.isEmpty()){
					String[] clockSetString =  commitPatchListString.split(Config.separator + Config.propertyClockPrefix);
					String projectKey = clockSetString[0].split(Config.equal)[1];
					for(int i = 1; i < clockSetString.length; i++){
						VectorClock clock = VectorClock.toVectorClock(clockSetString[i]);
						importVectorClockFromAllProject.put(projectKey, clock);
					}
				}
			}
			scn.close();
		return importVectorClockFromAllProject;
		}catch (Exception ex) {
		    ex.printStackTrace();
		    return null;
	    }
	}
	
	public static File exportLastAppliedCommitHashList(LastAppliedCommitHashList exportedLastAppliedCommitHashList, String projectName){
		HashMap<String, LastAppliedCommitHashList> lastAppliedCommitHashListFromAllProject = ExportImportHandler.importLastAppliedCommitHashListFromAllProject(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.lastAppliedCommitHashListFile);
		lastAppliedCommitHashListFromAllProject.put(projectName, exportedLastAppliedCommitHashList);
		try{
			File LastAppliedCommitHashFile = new File(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.lastAppliedCommitHashListFile);
			if(!LastAppliedCommitHashFile.exists()){
				LastAppliedCommitHashFile.createNewFile();
			}
			FileWriter fWriter = new FileWriter(LastAppliedCommitHashFile, false);
			int cnt = 0;
			for(String key : lastAppliedCommitHashListFromAllProject.keySet()){
				String outString = "";
				outString += lastAppliedCommitHashListFromAllProject.get(key).toString();
				if(cnt + 1 >= lastAppliedCommitHashListFromAllProject.size()){
					outString = Config.propertyProjectIdentity + Config.equal + key + Config.separator + Config.propertyHashPrefix + outString;
				}else{
					outString = Config.propertyProjectIdentity + Config.equal + key + Config.separator + Config.propertyHashPrefix +  outString + "\n";
				}
				fWriter.write(outString);
				cnt++;
			}
			fWriter.flush();
			fWriter.close();
			return LastAppliedCommitHashFile;
		} catch (Exception ex){
			ex.printStackTrace();
			return null;
		}
	}
	
	public static LastAppliedCommitHashList importLastAppliedCommitHashList(String commitHashListFileAbsolutePath, String projectName){
		LastAppliedCommitHashList lastAppliedCommitHashList = new LastAppliedCommitHashList();
		
		File commitPatchListFile = new File(commitHashListFileAbsolutePath);
		if(!commitPatchListFile.exists()){
			return lastAppliedCommitHashList;
		}
		HashMap<String, LastAppliedCommitHashList> lastAppliedCommitHashListFromAllProject = ExportImportHandler.importLastAppliedCommitHashListFromAllProject(commitHashListFileAbsolutePath);
		if(lastAppliedCommitHashListFromAllProject.size() >= 1){
			lastAppliedCommitHashList = lastAppliedCommitHashListFromAllProject.get(projectName);
			if(lastAppliedCommitHashList == null){
				return new LastAppliedCommitHashList();
			}
		}
		return lastAppliedCommitHashList;
	}
	
	public static HashMap<String, LastAppliedCommitHashList> importLastAppliedCommitHashListFromAllProject(String commitHashListFileAbsolutePath){
		HashMap<String, LastAppliedCommitHashList> lastAppliedCommitHashListFromAllProject = new HashMap<String, LastAppliedCommitHashList>();
		File commitHashListFile = new File(commitHashListFileAbsolutePath);
		if(!commitHashListFile.exists()){
			return lastAppliedCommitHashListFromAllProject;
		}
		try {
            Scanner scn = new Scanner(commitHashListFile);
			String commitPatchListString = null;
			while(scn.hasNextLine()){
				commitPatchListString = scn.nextLine();
				if(commitPatchListString != null && !commitPatchListString.isEmpty()){
					String[] commitPatchString =  commitPatchListString.split(Config.separator + Config.propertyHashPrefix);
					String projectKey = commitPatchString[0].split(Config.equal)[1];
					for(int i = 1; i < commitPatchString.length; i++){
						LastAppliedCommitHashList lastAppliedCommitHashList = LastAppliedCommitHashList.toLastAppliedCommitHashList(commitPatchString[i]);
						lastAppliedCommitHashListFromAllProject.put(projectKey, lastAppliedCommitHashList);
					}
				}
			}
			scn.close();
		return lastAppliedCommitHashListFromAllProject;
		}catch (Exception ex) {
		    ex.printStackTrace();
		    return null;
	    }
	}
	
	public static File exportCommitPatchList(List<CommitPatch> commitPatchList, String projectName){
		HashMap<String, List<CommitPatch>> commitPatchListFromAllProject = ExportImportHandler.importAllCommitPatchFromAllProjects(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.incomingCommitPatchListFile);
		commitPatchListFromAllProject.put(projectName, commitPatchList);
		try{
			File commitPatchListFile = new File(System.getProperty(Config.homeDirectoryNotation) + File.separator + Config.incomingCommitPatchListFile);
			if(!commitPatchListFile.exists()){
				commitPatchListFile.createNewFile();
			}
		
			FileWriter fWriter = new FileWriter(commitPatchListFile, false);
			int cnt = 0;
			for(String key : commitPatchListFromAllProject.keySet()){
				String outString = "";
				for(CommitPatch patch : commitPatchListFromAllProject.get(key)){
					outString += patch.toString();
				}
				if(cnt + 1 >= commitPatchListFromAllProject.size()){
					outString = Config.propertyProjectIdentity + Config.equal + key + Config.separator + outString;
				}else{
					outString = Config.propertyProjectIdentity + Config.equal + key + Config.separator + outString + "\n";
				}
				fWriter.write(outString);
				cnt++;
			}
			fWriter.flush();
			fWriter.close();
			return commitPatchListFile;
		} catch (Exception ex){
			ex.printStackTrace();
			return null;
		}
	}
	
	public static List<CommitPatch> importCommitPatch(String commitPatchListFileAbsolutePath, String projectName){
		List<CommitPatch> commitPatchList = new ArrayList<CommitPatch>();
		
		File commitPatchListFile = new File(commitPatchListFileAbsolutePath);
		if(!commitPatchListFile.exists()){
			return commitPatchList;
		}
		HashMap<String, List<CommitPatch>> commitPatchListFromAllProject = ExportImportHandler.importAllCommitPatchFromAllProjects(commitPatchListFileAbsolutePath);
		commitPatchList = commitPatchListFromAllProject.get(projectName);
		return commitPatchList;
	}
	
	public static HashMap<String, List<CommitPatch>> importAllCommitPatchFromAllProjects(String commitPatchListFileAbsolutePath){
		HashMap<String, List<CommitPatch>> commitPatchListFromAllProject = new HashMap<String, List<CommitPatch>>();
		
		File commitPatchListFile = new File(commitPatchListFileAbsolutePath);
		if(!commitPatchListFile.exists()){
			return commitPatchListFromAllProject;
		}
		
		try {
	           
            Scanner scn = new Scanner(commitPatchListFile);
			String commitPatchListString = null;
			while(scn.hasNextLine()){
				commitPatchListString = scn.nextLine();
				if(commitPatchListString != null && !commitPatchListString.isEmpty()){
					List<CommitPatch> commitPatchList = new ArrayList<CommitPatch>();
					String[] commitPatchString =  commitPatchListString.split(Config.separator + Config.propertyCommitPrefix);
					String projectKey = commitPatchString[0].split(Config.equal)[1];
					for(int i = 1; i < commitPatchString.length; i++){
						CommitPatch patch = new CommitPatch();
						patch = patch.toCommitPatch(commitPatchString[i]);
						commitPatchList.add(patch);
					}
					commitPatchListFromAllProject.put(projectKey, commitPatchList);
				}
			}
			scn.close();
		return commitPatchListFromAllProject;
		}catch (Exception ex) {
		    ex.printStackTrace();
		    return null;
	    }
	}
}
